using SharpDX.DirectInput;
using System;

namespace Engine.Input
{
    /// <summary>
    /// Creates a new Mouse-Device.
    /// </summary>
    public class MouseInput
    {
        #region Private Fields

        private int axisX, axisY, axisZ;
        private bool buttonL, buttonR, buttonM, buttonLreleased, buttonRreleased, buttonMreleased, mouseButtonLeft, mouseButtonRight, mouseLeftPressingStarted, mouseRightPressingStarted;
        private bool hasMovedWhilePressingL, hasMovedWhilePressingR, hasMovedWhilePressingM;
        private Mouse mouse = null;

        #endregion Private Fields

        #region Public Constructors

        /// <summary>
        /// Creates a new Mouse-Device and assign it to the given Form
        /// </summary>
        /// <param name="form">the form where the mouse interacting with</param>
        public MouseInput(IntPtr form)
        {
            DirectInput di = new DirectInput();
            mouse = new Mouse(di);
            mouse.SetCooperativeLevel(form, CooperativeLevel.Background | CooperativeLevel.NonExclusive);
            //mouse.SetDataFormat(DeviceDataFormat.Mouse);
            mouse.Acquire();
            Update();
        }

        #endregion Public Constructors

        #region Public Properties

        /// <summary>
        /// returns the Speed from the X-Axis
        /// </summary>
        public int AxisX
        {
            get
            {
                return axisX;
            }
        }

        /// <summary>
        /// returns the Speed from the Y-Axis
        /// </summary>
        public int AxisY
        {
            get
            {
                return axisY;
            }
        }

        /// <summary>
        /// returns the Speed from the Z-Axis
        /// </summary>
        public int AxisZ
        {
            get
            {
                return axisZ;
            }
        }

        /// <summary>
        /// Checks if the left mouse-button is pressed
        /// </summary>
        public bool ButtonL
        {
            get
            {
                return buttonL;
            }
        }

        /// <summary>
        /// Checks if the left mouse-button is pressed since the last Update
        /// </summary>
        public bool ButtonLeftPressingStarted
        {
            get
            {
                return mouseLeftPressingStarted;
            }
        }

        /// <summary>
        /// Checks if the left mouse-button is released since the last Update
        /// </summary>
        public bool ButtonLreleased
        {
            get
            {
                return buttonLreleased;
            }
        }

        /// <summary>
        /// Checks if the middle mouse-button is pressed
        /// </summary>
        public bool ButtonM
        {
            get
            {
                return buttonM;
            }
        }

        public bool ButtonMreleased
        {
            get { return buttonMreleased; }
            set { buttonMreleased = value; }
        }

        /// <summary>
        /// Checks if the right mouse-button is pressed
        /// </summary>
        public bool ButtonR
        {
            get
            {
                return buttonR;
            }
        }

        /// <summary>
        /// Checks if the right mouse-button is pressed since the last Update
        /// </summary>
        public bool ButtonRightPressingStarted
        {
            get
            {
                return mouseRightPressingStarted;
            }
        }

        /// <summary>
        /// Checks if the right mouse-button is released since the last Update
        /// </summary>
        public bool ButtonRreleased
        {
            get
            {
                return buttonRreleased;
            }
        }

        /// <summary>
        /// Checks if the Mouse has moved while pressing the Left Mousebutton.
        /// </summary>
        public bool HasMovedWhilePressingL
        {
            get
            {
                return hasMovedWhilePressingL;
            }
            set
            {
                hasMovedWhilePressingL = value;
            }
        }

        /// <summary>
        /// Checks if the Mouse has moved while pressing the Middle Mousebutton.
        /// </summary>
        public bool HasMovedWhilePressingM
        {
            get
            {
                return hasMovedWhilePressingM;
            }
            set
            {
                hasMovedWhilePressingM = value;
            }
        }

        /// <summary>
        /// Checks if the Mouse has moved while pressing the right Mousebutton.
        /// </summary>
        public bool HasMovedWhilePressingR
        {
            get
            {
                return hasMovedWhilePressingR;
            }
            set
            {
                hasMovedWhilePressingR = value;
            }
        }

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Read the new Mousestate and Updates the properties
        /// </summary>
        public void Update()
        {
            if (this.mouse.IsDisposed)
                return;
            MouseState state = new MouseState();
            state = mouse.GetCurrentState();
            axisX = state.X;
            axisY = state.Y;
            axisZ = state.Z;
            bool[] buttons = state.Buttons;

            buttonL = buttons.Length > 0 && buttons[0] != false; //state[Mouse.Button0];
            buttonR = buttons.Length > 0 && buttons[1] != false; //state[Mouse.Button1];
            buttonM = buttons.Length > 0 && buttons[2] != false; //state[Mouse.Button2];

            mouseLeftPressingStarted = false;
            mouseRightPressingStarted = false;

            if (buttonL)
            {
                if (buttonL == mouseButtonLeft)
                {
                    mouseLeftPressingStarted = false;
                }
                else
                {
                    mouseLeftPressingStarted = true;
                }
            }
            if (buttonR)
            {
                if (buttonR == mouseButtonRight)
                {
                    mouseRightPressingStarted = false;
                }
                else
                {
                    mouseRightPressingStarted = true;
                }
            }

            if (mouseButtonLeft != buttonL && !buttonL)
            {
                buttonLreleased = true;
            }
            else
            {
                buttonLreleased = false;
            }

            if (mouseButtonRight != buttonR && !buttonR)
            {
                buttonRreleased = true;
            }
            else
            {
                buttonRreleased = false;
            }

            if (!buttonL)
            {
                if (!buttonLreleased)
                {
                    hasMovedWhilePressingL = false;
                }
            }
            if (!buttonR)
            {
                if (!buttonRreleased)
                {
                    hasMovedWhilePressingR = false;
                }
            }
            if (!buttonM)
            {
                hasMovedWhilePressingM = false;
            }

            if (!hasMovedWhilePressingL)
            {
                if (buttonL)
                {
                    if (axisX != 0 || axisY != 0)
                    {
                        hasMovedWhilePressingL = true;
                    }
                }
            }

            if (!hasMovedWhilePressingR)
            {
                if (buttonR)
                {
                    if (axisX != 0 || axisY != 0)
                    {
                        hasMovedWhilePressingR = true;
                    }
                }
            }
            if (!hasMovedWhilePressingM)
            {
                if (buttonM)
                {
                    if (axisX != 0 || axisY != 0)
                    {
                        hasMovedWhilePressingM = true;
                    }
                }
            }

            mouseButtonLeft = buttonL;
            mouseButtonRight = buttonR;
        }

        #endregion Public Methods

        #region Internal Methods

        internal void Dispose()
        {
            this.mouse.Dispose();
        }

        #endregion Internal Methods
    }
}